window.Bytebuf = function (p) {

    this.readIndex = 0;
    this.writeIndex = 0;
    this.capacity = 256;
    this.macCapcity = 1024 * 1024;

    //buff初始化
    if (typeof p === 'undefined') {
        this.buff = new ArrayBuffer(this.capacity);
    } else if (typeof p === 'number') {
        this.capacity = p;
        if (this.capacity <= 0) {
            throw RangeError("Illegal capacity");
        }
        this.buff = new ArrayBuffer(this.capacity);
    } else if (typeof p === 'object' && p instanceof ArrayBuffer) {
        this.buff = p;
    } else if (typeof p === 'object' && p instanceof Array) {
        this.capacity = p.length;
        this.buff = new ArrayBuffer(p.length);
    } else {
        throw "can not create new bytebuf whit " + p;
    }

    //view初始化
    this.view = new DataView(this.buff);

    //数据初始化
    if (typeof p === 'object' && p instanceof Array) {
        for(var i = 0;i< p.length;i++){
            this.writeByte(p[i]);
        }
    }
}

/**
 * 获取读索引
 */
Bytebuf.prototype.readerIndex = function () {
    return this.readIndex;
}

/**
 * 获取写索引
 */
Bytebuf.prototype.writerIndex = function () {
    return this.writeIndex;
}

/**
 * 转换为字节数组
 */
Bytebuf.prototype.getBytes = function () {
    var byteArray = new Array(this.writeIndex);
    for (var i = this.readIndex; i < this.writeIndex; i++) {
        byteArray[i] = this.readByte();
    }
    return byteArray;
}

/**
 * 写入一个字节
 */
Bytebuf.prototype.writeByte = function (byteValue) {
    this.ensureWritable(1);
    this.view.setInt8(this.writeIndex, byteValue);
    this.writeIndex += 1;
}

/**
 * 写入一个UTF8字符串
 */
Bytebuf.prototype.writeUTF8 = function (utf8Value) {
    var bytes = this.utf2Bytes(utf8Value);
    this.ensureWritable(bytes.length);
    this.writeShort(bytes.length);
    for (var i = 0; i < bytes.length; i++) {
        this.writeByte(bytes[i])
    }
}

/**
 * 写入一个字节数组
 */
Bytebuf.prototype.writeByteArray = function (byteArray) {

    if (byteArray == null) {
        this.writeShort(0);
        return;
    }

    if (!(byteArray instanceof Array)) {
        throw "the byteArray need Array object";
    }

    this.writeShort(byteArray.length);
    for (var i = 0; i < byteArray.length; i++) {
        this.writeByte(byteArray[i]);
    }

}


/**
 * 将UTF8字符串转换为字节数组
 */
Bytebuf.prototype.utf2Bytes = function (str) {
    var bytes = new Array();
    var len, c;
    len = str.length;
    for (var i = 0; i < len; i++) {
        c = str.charCodeAt(i);
        if (c >= 0x010000 && c <= 0x10FFFF) {
            bytes.push(((c >> 18) & 0x07) | 0xF0);
            bytes.push(((c >> 12) & 0x3F) | 0x80);
            bytes.push(((c >> 6) & 0x3F) | 0x80);
            bytes.push((c & 0x3F) | 0x80);
        } else if (c >= 0x000800 && c <= 0x00FFFF) {
            bytes.push(((c >> 12) & 0x0F) | 0xE0);
            bytes.push(((c >> 6) & 0x3F) | 0x80);
            bytes.push((c & 0x3F) | 0x80);
        } else if (c >= 0x000080 && c <= 0x0007FF) {
            bytes.push(((c >> 6) & 0x1F) | 0xC0);
            bytes.push((c & 0x3F) | 0x80);
        } else {
            bytes.push(c & 0xFF);
        }
    }
    return bytes;
}

/**
 * 将字节数组转换为UTF8字符串
 */
Bytebuf.prototype.bytes2Utf8 = function (buf) {
    var i = 0;
    var pos = 0;
    var str = "";
    var unicode = 0;
    var flag = 0;
    for (pos = 0; pos < buf.length;) {
        flag = buf[pos];
        if ((flag >>> 7) === 0) {
            str += String.fromCharCode(buf[pos]);
            pos += 1;

        }
        else if ((flag & 0xFC) === 0xFC) {
            unicode = (buf[pos] & 0x3) << 30;
            unicode |= (buf[pos + 1] & 0x3F) << 24;
            unicode |= (buf[pos + 2] & 0x3F) << 18;
            unicode |= (buf[pos + 3] & 0x3F) << 12;
            unicode |= (buf[pos + 4] & 0x3F) << 6;
            unicode |= (buf[pos + 5] & 0x3F);
            str += String.fromCharCode(unicode);
            pos += 6;

        } else if ((flag & 0xF8) === 0xF8) {
            unicode = (buf[pos] & 0x7) << 24;
            unicode |= (buf[pos + 1] & 0x3F) << 18;
            unicode |= (buf[pos + 2] & 0x3F) << 12;
            unicode |= (buf[pos + 3] & 0x3F) << 6;
            unicode |= (buf[pos + 4] & 0x3F);
            str += String.fromCharCode(unicode);
            pos += 5;

        }
        else if ((flag & 0xF0) === 0xF0) {
            unicode = (buf[pos] & 0xF) << 18;
            unicode |= (buf[pos + 1] & 0x3F) << 12;
            unicode |= (buf[pos + 2] & 0x3F) << 6;
            unicode |= (buf[pos + 3] & 0x3F);
            str += String.fromCharCode(unicode);
            pos += 4;

        }

        else if ((flag & 0xE0) === 0xE0) {
            unicode = (buf[pos] & 0x1F) << 12;;
            unicode |= (buf[pos + 1] & 0x3F) << 6;
            unicode |= (buf[pos + 2] & 0x3F);
            str += String.fromCharCode(unicode);
            pos += 3;

        }
        else if ((flag & 0xC0) === 0xC0) { //110
            unicode = (buf[pos] & 0x3F) << 6;
            unicode |= (buf[pos + 1] & 0x3F);
            str += String.fromCharCode(unicode);
            pos += 2;

        }
        else {
            str += String.fromCharCode(buf[pos]);
            pos += 1;
        }
    }
    return str;

}

/**
 * 写入一个boolean值
 */
Bytebuf.prototype.writeBool = function (boolValue) {
    this.writeByte(boolValue ? 1 : 0);
}

/**
 * 写入一个short值 占2个字节
 */
Bytebuf.prototype.writeShort = function (shotValue) {
    this.ensureWritable(2);
    this.view.setInt16(this.writeIndex, shotValue);
    this.writeIndex += 2;
}

/**
 * 写入一个int值,占4个字节
 */
Bytebuf.prototype.writeInt = function (intValue) {
    this.ensureWritable(4);
    this.view.setInt32(this.writeIndex, intValue);
    this.writeIndex += 4;
}

/**
 * 写入一个long值,占8个字节
 */
Bytebuf.prototype.writeLong = function (longValue) {
    this.ensureWritable(8);
    this.view.setInt8(this.writeIndex,longValue>>>56);
    this.view.setInt8(this.writeIndex+1,longValue>>>48);
    this.view.setInt8(this.writeIndex+1,longValue>>>40);
    this.view.setInt8(this.writeIndex+1,longValue>>>32);
    this.view.setInt8(this.writeIndex+1,longValue>>>24);
    this.view.setInt8(this.writeIndex+1,longValue>>>16);
    this.view.setInt8(this.writeIndex+1,longValue);
    this.writeIndex += 8;
}

/**
 * 写入一个float值,占4个字节
 */
Bytebuf.prototype.writeFloat = function (floatValue) {
    this.ensureWritable(4);
    this.view.setFloat32(this.writeIndex, floatValue);
    this.writeIndex += 4;
}

/**
 * 写入一个double值,占8个字节
 */
Bytebuf.prototype.writeDouble = function (doubleValue) {
    this.ensureWritable(8);
    this.view.setFloat64(this.writeIndex, doubleValue);
    this.writeIndex += 8;
}

/**
 * 读取一个字节
 */
Bytebuf.prototype.readByte = function () {
    this.checkReadAbleBytes(1);
    var byteValue = this.view.getInt8(this.readIndex);
    this.readIndex += 1;
    return byteValue;
}

/**
 * 读取一个Boolean值
 */
Bytebuf.prototype.readBool = function () {
    return this.readByte() != 0;
}

/**
 * 读取一个short值
 */
Bytebuf.prototype.readShort = function () {
    this.checkReadAbleBytes(2);
    var shortValue = this.view.getInt16(this.readIndex);
    this.readIndex += 2;
    return shortValue;
}

/**
 * 读取一个int值
 */
Bytebuf.prototype.readInt = function () {
    this.checkReadAbleBytes(4);
    var intValue = this.view.getInt32(this.readIndex);
    this.readIndex += 4;
    return intValue;
}

/**
 * 读取一个long值
 */
Bytebuf.prototype.readLong = function () {
    this.checkReadAbleBytes(8);
    return (this.readByte() << 56|
            this.readByte() << 48|
            this.readByte() << 40|
            this.readByte() << 32|
            this.readByte() << 24|
            this.readByte() << 16|
            this.readByte() << 8|
            this.readByte());
}

/**
 * 读取一个float值
 */
Bytebuf.prototype.readFloat = function () {
    this.checkReadAbleBytes(4);
    var floatValue = this.view.getFloat32(this.readIndex);
    this.readIndex += 4;
    return floatValue;
}

/**
 * 读取一个double值
 */
Bytebuf.prototype.readDouble = function () {
    this.checkReadAbleBytes(8);
    var doubleValue = this.view.getFloat64(this.readIndex);
    this.readIndex += 8;
    return doubleValue;
}

/**
 * 读取一个utf8值
 */
Bytebuf.prototype.readUTF8 = function () {
    this.checkReadAbleBytes(2);
    var length = this.readShort();
    this.checkReadAbleBytes(length);
    var bytes = new Array(length);
    for (var i = 0; i < length; i++) {
        bytes[i] = this.readByte();
    }
    return this.bytes2Utf8(bytes);
}

/**
 * 读取一个字节数组
 */
Bytebuf.prototype.readByteArray = function () {
    this.checkReadAbleBytes(2);
    var length = this.readShort();
    var byteArray = new Array();
    for (var i = 0; i < length; i++) {
        byteArray[i] = this.readByte();
    }
    return byteArray;
}

Bytebuf.prototype.checkReadAbleBytes = function (minimumReadableBytes) {
    if (this.readerIndex > this.writerIndex - minimumReadableBytes) {
        throw RangeError("readerIndex(" + this.readIndex + ") + length(" + minimumReadableBytes + ") exceeds writerIndex(" + this.writeIndex + ")");
    }
}

Bytebuf.prototype.ensureWritable = function (minWritableBytes) {
    if (minWritableBytes < 0) {
        throw RangeError("Illegal minWritableBytes")
    }

    if (minWritableBytes > this.writeAbleBytes()) {
        if (minWritableBytes > this.macCapcity - this.writeIndex) {
            throw RangeError("max capacity");
        } else {
            var newCapcity = this.calculateNewCapacity(this.writeIndex + minWritableBytes);
            this.buff = ArrayBuffer.transfer(this.buff, newCapcity);
            this.view = new DataView(this.buff);
            this.capacity = newCapcity;
        }
    }
}

Bytebuf.prototype.writeAbleBytes = function () {
    return this.capacity - this.writeIndex;
}

Bytebuf.prototype.calculateNewCapacity = function (minNewCapacity) {
    var maxCapacity = this.maxCapacity;
    var threshold = 4194304;
    if (minNewCapacity == 4194304) {
        return 4194304;
    } else {
        var newCapacity;
        if (minNewCapacity > 4194304) {
            newCapacity = minNewCapacity / 4194304 * 4194304;
            if (newCapacity > maxCapacity - 4194304) {
                newCapacity = maxCapacity;
            } else {
                newCapacity += 4194304;
            }
            return newCapacity;
        } else {
            for (newCapacity = 64; newCapacity < minNewCapacity; newCapacity <<= 1) {
                ;
            }
            return newCapacity > maxCapacity ? maxCapacity:newCapacity;
        }
    }
}